import pyglet
from pyglet.window import key
pyglet.options['debug_gl'] = False
from pyglet.gl import *
import random,euclid
import ball,bat,brick,level,hud,intro
import zipfile
from pybass import *
import ctypes

class Game(pyglet.window.Window):
    def __init__(self):
        super(Game, self).__init__(640,480,visible=False,)
        
        pyglet.resource.path=['data.zip']
        pyglet.resource.reindex()

        # Flags
        self.OFF        = 0
        self.PRE        = 1 << 0
        self.PLAY       = 1 << 1
        self.PAUSE      = 1 << 2
        self.GAMEOVER   = 1 << 3
        self.INTRO      = 1 << 4
        self.INTRO1     = 1 << 5
        self.INTRO2     = 1 << 6
        self.INTRO3     = 1 << 7
        self.INTRO4     = 1 << 8
        self.INTRO5     = 1 << 9
        self.CREDITS    = 1 << 10

        # Sounds & music
        BASS_Init(-1,44100,0,0,0)

        self.playlist=[]
        self.playsize=[]
        self.wav_doh=None
        self.wav_woohoo=None
        self.wav_hit=None
        self.wav_wood=None
        self.wav_wall=None
        self.sound=True #used to toggle sound on/off
        self.music=True #used to toggle music on/off
        self.nsong=0 #Number of songs in playlist
        self.song=0 #Song in playlist to play
        self.channel=None # The music channel
        self.vol = 0.5 # Music channels volume
        self.syncProc = None
        
        self.LoadSounds()
        self.LoadMusic()
        self.PlayMusic()


        #load font
        pyglet.resource.add_font('ttf/BEWARE__.TTF')
        font=pyglet.font.load('Beware')

        self.state=self.INTRO | self.INTRO1
        self.intro=intro.Intro(self)
        self.intro_step=0.01

        self.lives=None
        self.score=None
        self.balls=None
        self.bricks=None
        self.nbricks=None
        self.lvl=None
        self.nlvl=None
        self.bat_size=None
        self.bat=None
        self.ball_size=None
        self.ball_speed=None

        self.batch=pyglet.graphics.Batch()

        self.walls=[]
        p01=euclid.Point2(0,0)
        p02=euclid.Point2(0,self.height)
        p03=euclid.Point2(self.width,self.height)
        p04=euclid.Point2(self.width,0)
        wall01=euclid.LineSegment2(p01,p02)
        wall02=euclid.LineSegment2(p02,p03)
        wall03=euclid.LineSegment2(p03,p04)
        wall04=euclid.LineSegment2(p04,p01)
        self.walls.append(wall01)
        self.walls.append(wall02)
        self.walls.append(wall03)
        self.walls.append(wall04)
        
        self.hud=hud.Hud(self)

        self.mx=0
        self.my=0
        self.nsurprise=10

        self.acc=0.
        self.dt=0.005

        self.NewGame()

        self.set_exclusive_mouse(True)        
        pyglet.clock.schedule_interval(self.Loop,1.0/60.0)        
        self.CenterScreen()
        self.set_visible()

    def LoadMusic(self):
        zip=zipfile.ZipFile('data.zip',"r")
        playlist=[]
        for name in zip.namelist():
            if (name.find('music/')==0):
                self.nsong+=1
                playlist.append(name)
        for name in playlist:
            for i in zip.infolist():
                if i.filename==name:
                    self.playsize.append(i.file_size)
            mod=zip.read(name)
            p=ctypes.c_char_p(mod)
            self.playlist.append(ctypes.cast(p, ctypes.c_void_p))
        zip.close()

    def SyncCallback(self,handle,channel,data,user):
        self.song+=1
        if self.song>self.nsong-1: self.song=0
        self.PlayMusic()

    def PlayMusic(self):
        self.channel=BASS_MusicLoad(1,self.playlist[self.song],0,self.playsize[self.song],BASS_MUSIC_STOPBACK,0)
        BASS_ChannelSetAttribute(self.channel,BASS_ATTRIB_VOL,self.vol)
        BASS_ChannelPlay(self.channel,1)
        self.syncProc = SYNCPROC(self.SyncCallback)
        BASS_ChannelSetSync(self.channel,BASS_SYNC_ONETIME | BASS_SYNC_END,0,self.syncProc,0)

    def LoadWav(self,name):
        zip=zipfile.ZipFile('data.zip',"r")
        wav=zip.read(name)
        for i in zip.infolist():
            if i.filename==name:
                size=i.file_size
        zip.close()
        p=ctypes.c_char_p(wav)
        return BASS_SampleLoad(1,ctypes.cast(p, ctypes.c_void_p),0,size,3,BASS_SAMPLE_OVER_POS)

    def LoadSounds(self):
        self.wav_hit=self.LoadWav('wavs/bat.wav')
        self.wav_doh=self.LoadWav('wavs/doh.wav')
        self.wav_woohoo=self.LoadWav('wavs/woohoo.wav')
        self.wav_wall=self.LoadWav('wavs/wall.wav')
        self.wav_wood=self.LoadWav('wavs/brick.wav')

    def NewGame(self):
        if not (self.state & self.INTRO): self.state=self.PRE
        self.nlvl=1
        self.hud.LabelLevel()
        self.lives=5
        self.hud.LabelLives()
        self.score=0
        self.hud.LabelScore()
        
        self.balls=[]
        self.ball_size=1
        self.ball_speed=100
        while True:
            rx=random.random()*random.randint(-1,1)
            if abs(rx)<0.6 and rx!=0:
                break
        b=ball.Ball(self,euclid.Vector2(0,0),euclid.Vector2(rx,-1.0).normalize(),0,self.ball_size)
        self.balls.append(b)

        self.bricks=[]
        self.nbricks=0
        if (self.lvl): del self.lvl
        self.lvl=level.Level(self)
        self.bat_size=1
        if self.bat: del self.bat
        self.bat=bat.Bat(self,self.bat_size)

    def ResizeBalls(self):
        bb=[]
        for b in self.balls:
            if b.surprise==0:
                bb.append(b)
                b.alive=False
        for b in bb:
            nb=ball.Ball(self,b.pos,b.dir,0,self.ball_size)
            self.balls.append(nb)

    def CenterScreen(self):
        x = (self.screen.width-self.width)//2
        y = (self.screen.height-self.height)//2
        self.set_location(x,y)
        
    def LoadImg(self,f):
        tmp=pyglet.resource.image(f)
        tmp.anchor_x=tmp.width//2
        tmp.anchor_y=tmp.height//2
        img=pyglet.sprite.Sprite(tmp)        
        del tmp
        return img

    def LoadStaticImg(self,f):
        tmp=pyglet.resource.image(f)
        tmp.anchor_x=tmp.width//2
        tmp.anchor_y=tmp.height//2
        img=pyglet.sprite.Sprite(tmp,batch=self.batch)
        del tmp
        return img

    def LoadAni(self,gif):
        tmp=pyglet.resource.animation(gif)
        tmp.anchor_x=tmp.get_max_width()//2
        tmp.anchor_y=tmp.get_max_height()//2
        ani=pyglet.sprite.Sprite(tmp)        
        del tmp
        return ani
    
    def Sweep(self):
        x=[]
        for b in self.balls:
            if not b.alive:
                x.append(b)
        for b in x:
            self.balls.remove(b)
        x=[]
        for b in self.bricks:
            if not b.alive:
                x.append(b)
        for b in x:
            self.bricks.remove(b)
            self.nbricks-=1
        if self.nbricks==0:
            self.state &= ~self.PLAY
            self.nlvl+=1
            self.hud.LabelLevel()
            if self.lvl: del self.lvl
            self.lvl=level.Level(self)
            self.state |= self.PRE
    
    def Loop(self,dt):
        self.acc+=dt
        while (self.acc>=self.dt):
            if self.state & self.PLAY:
                self.Sweep()            
            if self.state & (self.PLAY | self.PRE):
                for b in self.bricks:
                    b.Loop()
                for b in self.balls:
                    b.Loop(dt)
                self.bat.Loop(self.mx)
            if self.state & self.INTRO:
                if self.state & self.INTRO1:
                    self.intro.alpha-=self.intro_step
                    if self.intro.alpha<=0:
                        self.state &= ~self.INTRO1
                        self.state |= self.INTRO2
                if self.state & self.INTRO2:
                    self.intro.alpha+=self.intro_step
                    if self.intro.alpha>=1:
                        self.state &= ~self.INTRO2
                        self.state |= self.INTRO3
                if self.state & self.INTRO3:
                    self.intro.alpha-=self.intro_step
                    if self.intro.alpha<=0:
                        self.state &= ~self.INTRO3
                        self.state |= self.INTRO4
                if self.state & self.INTRO4:
                    self.intro.alpha+=self.intro_step
                    if self.intro.alpha>=1:
                        self.state &= ~self.INTRO4
                        self.state |= self.INTRO5
            self.acc-=self.dt
            
    def on_draw(self):
        self.clear()
        if self.state & (self.INTRO | self.CREDITS):
            self.intro.Draw()
        elif self.state & self.PRE | self.PLAY:
            self.batch.draw()
            for b in self.balls:
                b.Draw()
            self.bat.Draw()
            self.hud.Draw()
            
    def on_key_press(self, symbol, modifiers):
        if symbol == key.F:
            self.hud.showfps=not self.hud.showfps
        elif symbol == key.P:
            if not self.state & (self.PRE | self.INTRO | self.CREDITS | self.GAMEOVER):
                if self.state & self.PAUSE:
                    self.state &= ~self.PAUSE
                    self.state |= self.PLAY
                    BASS_Start()
                else:
                    self.state &= ~self.PLAY                    
                    self.state |= self.PAUSE
                    BASS_Pause()
        elif symbol == key.S:
            self.sound=not self.sound
        elif symbol == key.M:
            self.music=not self.music
            if self.music:
                BASS_ChannelPlay(self.channel,0)
            else:
                BASS_ChannelPause(self.channel)
        elif symbol == key.ESCAPE:
            if self.state & self.CREDITS:
                self.close()
            elif self.state & self.INTRO:
                self.state &= ~self.INTRO
                if self.state & self.INTRO1: self.state &= ~self.INTRO1
                if self.state & self.INTRO2: self.state &= ~self.INTRO2
                if self.state & self.INTRO3: self.state &= ~self.INTRO3
                if self.state & self.INTRO4: self.state &= ~self.INTRO4
                if self.state & self.INTRO5: self.state &= ~self.INTRO5 
                self.state |= self.PRE
            elif self.state & (self.PRE | self.PLAY | self.GAMEOVER):
                if self.state & self.PRE: self.state &= ~self.PRE
                if self.state & self.PLAY: self.state &= ~self.PLAY
                if self.state & self.GAMEOVER: self.state &= ~self.GAMEOVER
                self.state |= self.CREDITS
            else:
                pass
        elif symbol == key.UP:
            self.vol+=0.1
            if self.vol>1: self.vol=1
            BASS_ChannelSetAttribute(self.channel,BASS_ATTRIB_VOL,self.vol)
        elif symbol == key.DOWN:
            self.vol-=0.1
            if self.vol<0: self.vol=0
            BASS_ChannelSetAttribute(self.channel,BASS_ATTRIB_VOL,self.vol)
        elif symbol == key.LEFT:
            self.song-=1
            if self.song<0: self.song=self.nsong-1
            BASS_ChannelStop(self.channel)
            self.PlayMusic()
        elif symbol == key.RIGHT:
            self.song+=1
            if self.song>self.nsong-1: self.song=0
            BASS_ChannelStop(self.channel)
            self.PlayMusic()

    def on_mouse_motion(self, x, y, dx, dy):
        self.mx+=dx
        self.my+=dy
        if self.state & self.PAUSE:
            self.state &= ~self.PAUSE
            self.state |= self.PLAY
            BASS_Start()
    
    def on_mouse_press(self, x, y, button, modifiers):
        if self.state & self.PRE:
            self.state &= ~self.PRE
            self.state |= self.PLAY
        elif self.state & self.GAMEOVER:
            self.state &= ~self.GAMEOVER
            self.NewGame()
        elif self.state & self.INTRO5:
            #glDisable(GL_BLEND)
            #glEnable(GL_DEPTH_TEST)
            #glBlendFunc(GL_ONE,GL_ONE)
            self.state &= ~self.INTRO5
            self.state &= ~self.INTRO
            self.state |= self.PRE
        elif self.state & self.CREDITS:
            self.close()
        else:
            pass

    def on_mouse_scroll(self, x, y, scroll_x, scroll_y):
        pass
        
def main():
    game = Game()
    pyglet.app.run()

def profile_main():
    # This is the main function for profiling 
    import cProfile, pstats
    prof = cProfile.Profile()
    prof = prof.runctx("main()", globals(), locals())
    print "<pre>"
    stats = pstats.Stats(prof)
    stats.sort_stats("time")  # Or cumulative
    stats.print_stats(80)  # 80 = how many to print
    # The rest is optional.
    # stats.print_callees()
    # stats.print_callers()
    print "</pre>"

if __name__ == "__main__":
    #profile_main()
    main()

